package com.jiuxian.scheduling.util;

import com.jiuxian.scheduling.listener.zk.ZkChildListener;
import com.jiuxian.scheduling.listener.zk.ZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.apache.commons.lang3.StringUtils;
import org.apache.zookeeper.CreateMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * Created by wangjingqing on 2017/11/8.
 * @author wangjingqing
 */
public class ZKClientUtil {

    static Logger logger = LoggerFactory.getLogger(ZKClientUtil.class);

    /** 根节点名称 */
    private static final String ROOT_NODE = "/scheduling";

    public static final String ROOT_LOCK = "/lock";

    protected static ZkClient zk;
    //初始化zk
    static {
        //zk地址
        try {
            String zkAddress = ConfigUtil.getValue("zk.address");
            //连接超时时间
            synchronized (ROOT_NODE){
                if(zk == null){
                    String connectionTimeOut = ConfigUtil.getValue("zk.connection.timeout");
                    zk = new ZkClient(zkAddress,StringUtils.isBlank(connectionTimeOut) || !StringUtils.isNumeric(connectionTimeOut)?5000:Integer.valueOf(connectionTimeOut));
                    //初始跟节点
                    initRootNode();
                }
            }
        } catch (NumberFormatException e) {
            logger.error("初始化zk失败");
            throw new RuntimeException("初始化zk失败,请检查ZK");
        }

        //关闭连接
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                if(null != zk){
                    zk.close();
                }
            }
        }));
    }

    /**
     * 创建节点<br>
     * @param path 路径
     */
    public static void creatNode(String path,Object data){
        checkZK();
        if(!exists(path)){
            zk.createPersistent(ROOT_NODE +"/"+ path, data);
            //增加监听
            addDataListener(path,new ZkDataListener());
        }
    }


    /**
     * 设置节点数据<br>
     * @param path 路径
     * @param data 数据
     * @return boolean
     */
    public static boolean setDate(String path,Object data){
        checkZK();
        if(!exists(path)){
            logger.error("路径{}节点不存在",path);
           return false;
        }
        zk.writeData(ROOT_NODE +"/"+  path,data);
        return true;
    }

    /**
     * 删除节点<Br>
     * @param path 路径
     * @return boolean
     */
    public static boolean delNode(String path){
        checkZK();
        if(exists(path)){
            zk.deleteRecursive(ROOT_NODE + "/"+  path);
        }
        return true;
    }


    /**
     * 节点增加监听<br>
     * @param path 路径
     * @param listener 监听
     */
    public static void addDataListener(String path,ZkDataListener listener){
        checkZK();
        if(!exists(path)){
            logger.error("路径{}节点不存在",path);
            return;
        }
        zk.subscribeDataChanges(ROOT_NODE + "/"+  path,listener);
    }

    public static void addRootNodeListener(ZkChildListener listener){
        checkZK();
        if(zk.exists(ROOT_NODE)){
            zk.subscribeChildChanges(ROOT_NODE,listener);
        }
    }
    /**
     * 获取节点上数据信息<br>
     * @param path 路径
     * @return Object
     */
    public static Object getData(String path){
        checkZK();
        if(!exists(path)){
            return null;
        }
        return zk.readData(ROOT_NODE+"/"+path);
    }
    /**
     * 判断节点是否存在<br>
     * @param path 路径
     * @return
     */
    public static boolean exists(String path){
        return zk.exists(ROOT_NODE+"/"+path);
    }

    /**
     * 检查zk
     */
    private static void checkZK(){
        if (null == zk){
            throw new RuntimeException("zk 初始化异常");
        }
    }

    public static List<String> getNodes(){
        return zk.getChildren(ROOT_NODE);
    }
    /**
     * 初始根节点<br>
     */
    private static void initRootNode(){
        if(!zk.exists(ROOT_NODE)){
            zk.create(ROOT_NODE,ROOT_NODE,CreateMode.PERSISTENT);
        }
        addRootNodeListener(new ZkChildListener());
    }


    /**
     * 初始化锁根节点节点<br>
     */
    public static void createNode(String path){
        checkZK();
        if(!zk.exists(path)){
            zk.createPersistent(path);
        }
    }

}
